const http = require('http')
const url = require('node:url')
const path = require('path')
const fs = require('fs')
const mime = require('mime')
const { promisify } = require('util')
const ejs = require('ejs')

const handleConfigMerge = (config) => ({
  port: 7777,
  directory: process.cwd(),
  ...config
})

class Server {
  constructor (config) {
    this.config = handleConfigMerge(config)
  }

  start () {
    const server = http.createServer(this.serverHandle.bind(this))
    server.listen(this.config.port, () => {
      console.log(`Succeed! The Server running at http://localhost:${this.config.port}`)
    })
  }

  async serverHandle (req, res) {
    let { pathname } = url.parse(req.url)
    pathname = decodeURIComponent(pathname) // 兼容中文
    const absPath = path.join(this.config.directory, pathname)
    const fsStat = promisify(fs.stat)
    try {
      const stats = await fsStat(absPath)
      if (stats.isFile()) {
        this.fileHandle(absPath, req, res)
      } else {
        await this.dirHandle(req, res, absPath, pathname)
      }
    } catch (err) {
      this.errorHandle(err, req, res)
    }
  }

  fileHandle (absPath, req, res) {
    this.successHandle(absPath, req, res)
    fs.createReadStream(absPath).pipe(res)
  }

  async dirHandle (req, res, absPath, pathname) {
    const fsReaddir = promisify(fs.readdir)
    try {
      let dirs = await fsReaddir(absPath)
      dirs = dirs.map(dir => {
        return {
          dir,
          path: path.join(pathname, dir)
        }
      })
      const templatePath = path.resolve(__dirname, 'template.html')
      const file = await ejs.renderFile(templatePath, {
        dirs,
        isRoot: pathname === '/',
        prevDirPath: path.dirname(pathname),
        currentDirName: path.basename(absPath),
        currentDirPath: absPath
      })
      this.successHandle(templatePath, req, res)
      res.end(file)
    } catch (err) {
      this.errorHandle(err, req, res)
    }
  }

  errorHandle (err, req, res) {
    console.error(err)
    res.statusCode = 404
    res.setHeader('Content-type', 'text/html;charset=utf-8')
    res.end('Not Found')
  }

  successHandle (path, req, res) {
    res.statusCode = 200
    let contentType = mime.getType(path)
    contentType = contentType || 'text/plain'
    res.setHeader('Content-type', `${contentType};charset=utf-8`)
  }
}

module.exports = Server
